home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / networking / pgpuam / sources / pgpuamclient.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  16.2 KB  |  576 lines

  1. /*
  2.     File:            PGPUAMclient.c
  3.  
  4.     Description:     PGP Appleshare User Authentication Module
  5.  
  6.     Written by:    Vinnie Moscaritolo
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. //------------------------------------------------------------------------------------
  22. #pragma mark Includes
  23. //------------------------------------------------------------------------------------
  24. #include <Errors.h>
  25. #include <String.h>
  26. #include <A4Stuff.h>
  27. #include <Resources.h>
  28. #include <MixedMode.h>
  29. #include <Appearance.h>
  30. #include <CodeFragments.h>
  31. #include <Gestalt.h>
  32. #include <PLStringFuncs.h>
  33.  
  34. #include "ClientUAM.h" 
  35. #include "AFPPackets.h"
  36.  
  37. #include <stdio.h>
  38.  
  39. #include "TPGPkey.h"
  40. #include "TPGPException.h"
  41. #include "TMacException.h"
  42. #include "TASIPPGPkey.h"
  43. #include "ASIPChallenge.h"
  44. #include "PGPUAMdefines.h"
  45. #include "PGPUAMclient.h"
  46. #include "PGPUAMclientLoginDialog.h"
  47. #include "PGPUAMclientProtocol.h"
  48. #include "PGPUAMmsgFormat.h"
  49. #include "PGPUAMclient.h"
  50. #include "TPGPUAMPrefs.h"
  51. #include "pgpUserInterface.h"
  52.  
  53.  
  54.  
  55. // ---------------------------------------------------------------------------
  56. #pragma mark Exported Symbols
  57. // ---------------------------------------------------------------------------
  58.  
  59. #ifdef __cplusplus
  60. extern "C" {
  61. #endif
  62. #pragma export on
  63.     extern  const long __procinfo = kUAMCallProcInfo;
  64.             OSErr        __pgpuam_initialize(CFragInitBlockPtr ibp);
  65.             void        __pgpuam_terminate(void);
  66.     pascal     OSStatus     __pgpuam_client (UAMArgs *theArgs);
  67.  
  68.     pascal OSErr __initialize(const CFragInitBlock *theInitBlock);
  69.     pascal OSErr __terminate(void);
  70.     #pragma export off
  71.  
  72.  
  73. #ifdef __cplusplus
  74. }
  75. #endif
  76.  
  77.  
  78. // ---------------------------------------------------------------------------
  79. #pragma mark Globals
  80. // ---------------------------------------------------------------------------
  81.     AFPSrvrInfo *    gAFPServerInfo    = nil;
  82.     AFPClientInfo *    gClientInfo     = nil;
  83.     UInt8 *            gAFPSrvrSig     = nil;
  84.  
  85. // ---------------------------------------------------------------------------
  86. #pragma mark Local Prototypes
  87. // ---------------------------------------------------------------------------
  88.  
  89. static    OSStatus    PGPUAMOpen    (UAMArgs *theArgs);
  90. static    OSStatus    PGPUAMClose (UAMArgs *theArgs);
  91. static    OSStatus    PGPUAMLogin (UAMArgs *theArgs);
  92.  
  93.  
  94. static     OSStatus     InitiateConnection (StringPtr userName, 
  95.                                         StringPtr serverName,
  96.                                         short *sessionRefNum, 
  97.                                         TPGPUAMPrefs *userPrefs, 
  98.                                         TASIPPGPkey *serverKey, 
  99.                                         IdleConnectionProcPtr idleProc, 
  100.                                         void* context );
  101.                                         
  102. static     void         TerminateConnection (void* context);
  103.  
  104. static StringPtr     FigureAFPVersion(    AFPSrvrInfo *info,ClientUAMCallbackRec *callbacks);
  105. static Boolean         FindStringInBuf(    StringPtr string, Ptr buf, UInt32 bufSize);
  106.  
  107. static void         PostError(short errorStrId, short explanStrID);
  108.  
  109. // test code..
  110.  
  111. // ---------------------------------------------------------------------------
  112. OSErr __pgpuam_initialize(CFragInitBlockPtr ibp)
  113. // ---------------------------------------------------------------------------
  114. //
  115. //  PGPUAM Library Initialization
  116. //
  117.  
  118. {
  119.       long    gestaltResult;
  120.     OSErr    err = -1;
  121.     
  122.     /*
  123.     ** Check for a 68020 or later processor and bail immediately if
  124.     ** none is available.
  125.     */
  126. //DebugStr("\p__pgpuam_initialize");
  127.  
  128.     if( Gestalt( gestaltProcessorType, &gestaltResult ) == noErr &&
  129.         gestaltResult >= gestalt68020 )
  130.         {
  131.             err = __initialize( ibp );
  132.          }
  133.  
  134.      return err;
  135. }
  136.  
  137.  
  138. // ---------------------------------------------------------------------------
  139. void __pgpuam_terminate(void)
  140. // ---------------------------------------------------------------------------
  141. //
  142. //  PGPUAM Library Termination
  143. //
  144.  
  145. {
  146.     __terminate();
  147. }
  148.  
  149.  
  150. #pragma mark -
  151. // ---------------------------------------------------------------------------
  152. pascal OSStatus __pgpuam_client(UAMArgs *theArgs)
  153. // ---------------------------------------------------------------------------
  154. {
  155.      OSStatus    error;
  156.     char         errorBuf[256];
  157.     char         explanationBuf[256];
  158. //    ostrstream err( errorBuf,256);
  159. //    ostrstream explain( explanationBuf,256);
  160.  
  161.       EnterCodeResource();
  162.     try
  163.     {
  164.          switch(theArgs->command)
  165.         {
  166.             case    kUAMOpen:
  167.     //            DebugStr("\pUAMCall - kUAMOpen");
  168.                 error =    PGPUAMOpen(theArgs);
  169.                 break;
  170.                                     
  171.             case    kUAMPWDlog:
  172.     //            DebugStr("\pUAMCall - kUAMPWDlog");
  173.                 error =    noErr;
  174.                 break;
  175.  
  176.             case    kUAMLogin:
  177.     //            DebugStr("\pUAMCall - kUAMLogin");
  178.                  error =    PGPUAMLogin(theArgs);
  179.                 break;
  180.             
  181.             case    kUAMVSDlog:
  182.     //            DebugStr("\pUAMCall - kUAMVSDlog");
  183.                 error =    noErr;
  184.                 break;
  185.  
  186.             case    kUAMChgPassDlg:
  187.                 DebugStr("\pUAMCall - kUAMChgPassDlg");
  188.                 error =    kNotForUs;
  189.                 break;
  190.  
  191.             case    kUAMChgPass:
  192.                 DebugStr("\pUAMCall - kUAMChgPass");
  193.                 error =    kNotForUs;
  194.                 break;
  195.  
  196.             case    kUAMGetInfoSize:
  197.                 DebugStr("\pUAMCall - kUAMGetInfoSize");
  198.     //            uamInfoSize = n;
  199.                 error =    kNotForUs;
  200.                 break;
  201.  
  202.             case    kUAMGetInfo:
  203.                 DebugStr("\pUAMCall - kUAMGetInfo");
  204.     //            uamInfo < == 
  205.                 error =    kNotForUs;
  206.                 break;
  207.  
  208.             case    kUAMClose:
  209.     //            DebugStr("\pUAMCall - kUAMClose");
  210.                 error =    PGPUAMClose(theArgs);
  211.                 break;
  212.  
  213.             default:
  214.                 DebugStr("\psome other UAMCall");
  215.                 error =    kNotForUs;
  216.                 break;
  217.         }
  218.     }
  219.     catch (TMacException &ex)
  220.     {
  221.         SInt16             itemHit;
  222.     
  223.         error = theArgs->result = ex.GetExceptionErr(); 
  224.          if(error == noErr) 
  225.                  error = userCanceledErr;
  226.  
  227.         errorBuf[0] = sprintf(&errorBuf[1], "%s\rPGPUAM Error: %d\rFile: %s, Line: %d",  
  228.                              ex.GetExceptionMessage(),  ex.GetExceptionErr(), ex.GetExceptionFile(), ex.GetExceptionLine());
  229.                              
  230.         StandardAlert(kAlertStopAlert,"\pThe PGP Challenge/Response UAM could not be used.", 
  231.                                         (UInt8 *) errorBuf, nil , &itemHit);
  232.     }
  233.  
  234. // handle PGP errors
  235.     catch (TPGPException &ex)
  236.     {
  237.         SInt16             itemHit;
  238.          PGPGetErrorString ( ex.GetExceptionErr(), sizeof(explanationBuf), explanationBuf);
  239.         
  240.         errorBuf[0] = sprintf(&errorBuf[1], "%s\r\rPGPUAM Error: %d\rFile: %s, Line: %d",  
  241.                             ex.GetExceptionMessage(),  ex.GetExceptionErr(),  ex.GetExceptionFile(),  ex.GetExceptionLine());
  242.     
  243.         c2pstr(explanationBuf);
  244.          StandardAlert(kAlertStopAlert,(UInt8 *)errorBuf, (UInt8 *)explanationBuf, nil , &itemHit);
  245.         error = theArgs->result = userCanceledErr; 
  246.     }
  247.  
  248.      ExitCodeResource();
  249.     return error;
  250.  
  251. // ---------------------------------------------------------------------------
  252. static OSStatus    PGPUAMOpen(UAMArgs *theArgs)
  253. // ---------------------------------------------------------------------------
  254.  {
  255.       OSStatus    ErrNo ;    
  256.      long        response = 0;
  257.  
  258. // Get the AppleShare Client info
  259.     ErrNo = CallUniversalProc( theArgs->callbacks->GetClientInfoUPP, kGetClientInfoProcInfo,  kAFPClientInfo, &gClientInfo);
  260.     if(ErrNo != noErr) return ErrNo;
  261.     
  262. // check agaisnt client versions
  263.     ThrowMsgIfNot ( (gClientInfo->fVersion > 8), 
  264.         "This UAM requires AppleShare Client 3.8.1 or later");
  265.     
  266. // Save the server info pointer.
  267.       gAFPServerInfo  = theArgs->Opt.open.srvrInfo;
  268.       
  269. // calculate server signature block.
  270.         UInt8             *signatureOffset;
  271.         signatureOffset =  (&gAFPServerInfo->fSrvrName[0] + gAFPServerInfo->fSrvrName[0] + 1);
  272.         if ( (UInt32)signatureOffset & 0x01) signatureOffset++;
  273.          gAFPSrvrSig = ((UInt8*) gAFPServerInfo)  + * ((short*)signatureOffset);
  274.  
  275. // Is  Appearance Mgr available ?
  276.      ThrowMsgIfNot ( ((Gestalt(gestaltAppearanceAttr, &response) == noErr) 
  277.                     && ((long)RegisterAppearanceClient != kUnresolvedCFragSymbolAddress)) ,
  278.          "Appearance Mgr is required");     
  279.  
  280.  // collection manager too
  281.     ThrowMsgIfNot ( ((Gestalt(gestaltCollectionMgrVersion, &response) == noErr) 
  282.                     && ((long)NewCollection != kUnresolvedCFragSymbolAddress)) ,
  283.          "Collection Mgr is required");     
  284.  
  285. // Is  PGPsdk available ?
  286.      ThrowMsgIfNot ((long)PGPNewContext != kUnresolvedCFragSymbolAddress,
  287.          "PGPsdk is required");     
  288.  
  289. // Is  PGPsdkUIlib available ?
  290.      ThrowMsgIfNot ((long)PGPSigningPassphraseDialog != kUnresolvedCFragSymbolAddress ,
  291.          "PGPsdkUIlib is required");     
  292.  
  293. // Create a new PGP context
  294.     TPGPkey::Initialize();
  295.  
  296. // establish link to PassphraseCache
  297. //???
  298.  
  299.      theArgs->result = ((1 << kUsePWDlog) | (1 << kUseUAMInfo)) ;
  300.     return noErr;
  301. }
  302.  
  303. // ---------------------------------------------------------------------------
  304. static OSStatus    PGPUAMLogin(UAMArgs *theArgs)
  305. // ---------------------------------------------------------------------------
  306. {
  307.     TPGPUAMPrefs*    userPrefs    = nil;
  308.     Str63            userName;
  309.  
  310. // Get user prefs     
  311.     userPrefs = new  TPGPUAMPrefs();
  312.     userPrefs->Initialize();
  313.  
  314. // open the keyring    
  315.     TPGPkey::OpenKeyDefaultRing();
  316.  
  317. // if no username was specified.. (Alias resolution)
  318. // Initiate the connection w/o UI
  319.     if(theArgs->Opt.auth.userName[0] != '\0')
  320.     {
  321.         TASIPPGPkey        theServerKey;
  322.         
  323.     // copy the user name from the authblock
  324.         PLstrcpy( userName, theArgs->Opt.auth.userName);
  325.     
  326.     
  327.     // pickup the server key
  328.         theServerKey.Initialize(gAFPSrvrSig);
  329.         
  330.     // initiate connection directly
  331.         theArgs->result = InitiateConnection(userName, gAFPServerInfo->fSrvrName, &theArgs->sessionRefNum, userPrefs, &theServerKey, nil, theArgs);
  332.     
  333.      } 
  334.     else 
  335.     {
  336.      // copy the default user name.
  337.         PLstrcpy( userName, gClientInfo->fDefaultUserName);
  338.  
  339.      // initiate connection with User Interface
  340.         theArgs->result = DoLoginDialog( userName, 
  341.                                          gAFPServerInfo->fSrvrName,
  342.                                          &theArgs->sessionRefNum,
  343.                                          userPrefs,
  344.                                          InitiateConnection,
  345.                                          TerminateConnection,
  346.                                          theArgs->callbacks->EventCallbackUPP,
  347.                                          theArgs);
  348.  
  349.     // put username into the authblock buffer for later Alias resolution
  350.         PLstrcpy(theArgs->Opt.auth.userName, userName);
  351.         
  352.     // not clear if I should post the error or not
  353.     // you might want to take out the next line...
  354.         if(( theArgs->result != noErr) && (theArgs->result != userCanceledErr))
  355.              PostError( kErrOther, kErrOtherExplanation);
  356.     }
  357.  
  358. // close the keyring
  359.     TPGPkey::CloseKeyRing();
  360.  
  361. // update user prefs
  362.     userPrefs->Finalize();
  363.     delete userPrefs;
  364.         
  365.       return (theArgs->result) ;
  366. }
  367.  
  368. // ---------------------------------------------------------------------------
  369. static OSStatus    PGPUAMClose(UAMArgs *theArgs)
  370. // ---------------------------------------------------------------------------
  371.  {
  372.  
  373. // remove PGP context        
  374.         TPGPkey::Finalize();
  375.         
  376.     return noErr;
  377. }
  378.  
  379. #pragma mark -
  380.  
  381.  
  382. // ---------------------------------------------------------------------------
  383. static OSStatus InitiateConnection( StringPtr    userName,
  384.                                         StringPtr    serverName, 
  385.                                      short       *sessionRefNum,
  386.                                      TPGPUAMPrefs *userPrefs,
  387.                                      TASIPPGPkey    *serverKey,
  388.                         IdleConnectionProcPtr    idleProc,
  389.                                      void*        context)
  390. // ---------------------------------------------------------------------------
  391. {
  392.     UAMArgs         *theArgs = (UAMArgs *) context;
  393.     PUAM_LOGIN_RESP    resp;
  394.     StringPtr        serverVersion;
  395.     Str63             challengeString;
  396.     Str63             answerString;
  397.     Str255            promptString;
  398.  
  399.     UInt8            replyBuffer[256];
  400.     UInt32              replyBufferSize;
  401.     Handle            uamName;
  402.       OSStatus        ErrNo ;        
  403.   
  404.     // calculate which AFPversion we will use.
  405.     serverVersion = FigureAFPVersion(gAFPServerInfo,theArgs->callbacks);
  406.      if(!serverVersion){
  407.         // put up an alert & return userCancelled error
  408.         DebugStr("\pno AFP version returned by server");
  409.         return userCanceledErr;
  410.     }
  411.  
  412.     // get the UAMSTring from the resource
  413.     uamName = Get1Resource(kUAMStr,kUAMProtoName);
  414.     ThrowMacErrIfNil(uamName, ResError());
  415.     
  416.     // Calculate Challenge String    
  417.     MakeChallenge(serverKey, challengeString);
  418.     
  419.     // send OpenSession command to server.
  420.     HLock(uamName);
  421.     ErrNo = SndLoginCmd(    theArgs->callbacks,
  422.                             serverVersion, (StringPtr) *uamName,  userName, 
  423.                             challengeString,
  424.                             theArgs->Opt.auth.srvrAddress, 
  425.                             replyBuffer,   sizeof (replyBuffer),  &replyBufferSize,                 
  426.                             sessionRefNum,
  427.                             idleProc);     
  428.     HUnlock(uamName);
  429.      if( ErrNo != kFPAuthContinue )    return ErrNo;
  430.      ErrNo = userCanceledErr;
  431.      
  432.     // parse the reply
  433.      ParseLoginResp(replyBuffer,  &replyBufferSize, &resp);
  434.  
  435.     // check the reply
  436.     if( !  VerifyChallenge(serverKey, challengeString, resp.CounterChallengePString))
  437.     {
  438.  
  439. // warn user that server didnt check out!
  440.         Str255         errorBuf, explainBuf;
  441.         SInt16         itemHit;
  442.         AlertStdAlertParamRec aRec;
  443.         
  444.         aRec.movable     = true;
  445.         aRec.helpButton    = false;
  446.         aRec.filterProc = nil;
  447.         aRec.defaultText =  userPrefs->GetAuthenticateServer()? (unsigned char*) -1 : "\pAbort";
  448.          aRec.cancelText     =  userPrefs->GetAuthenticateServer()? nil:"\pContinue";
  449.          aRec.otherText     = nil;
  450.         aRec.defaultButton = kAlertStdAlertOKButton;
  451.         aRec.cancelButton  = kAlertStdAlertCancelButton;
  452.         aRec.position  = kWindowAlertPositionParentWindowScreen;
  453.             
  454.         GetIndString(errorBuf, kErrorStringsID, kErrUnableToAuthErr);
  455.         PLstrcat(errorBuf, "\p\"");
  456.         PLstrcat(errorBuf, serverName);
  457.         PLstrcat(errorBuf, "\p\".");
  458.         GetIndString(explainBuf, kErrorStringsID,  userPrefs->GetAuthenticateServer() ? kErrUnableToAuthExplanation: kErrUnableToAuthContinueExplanation);
  459.         
  460.          StandardAlert(kAlertCautionAlert, errorBuf, explainBuf, &aRec , &itemHit);
  461.            
  462.          if(itemHit == kAlertStdAlertOKButton) return userCanceledErr;
  463.      };
  464.  
  465.     // build custom prompt string
  466.     PLstrcpy(promptString, "\pTo connect to \"");
  467.      PLstrcat(promptString, serverName);
  468.      PLstrcat(promptString, "\p\", please enter the passphrase for the following key.");
  469.     p2cstr(promptString);
  470.     
  471.      ErrNo = ReplyToCounterChallenge(promptString, resp.FingerPrintPString, resp.CounterChallengePString, answerString);
  472.     if(ErrNo == userCanceledErr) return ErrNo;
  473.     
  474.     if(ErrNo != noErr)
  475.     {
  476.         PostError(kErrClientUnableToAuthErr, kErrClientUnableToAuthExplanation);
  477.          return userCanceledErr;
  478.     }
  479.     
  480.      ErrNo = SndLoginContinueCmd(theArgs->callbacks, *sessionRefNum, answerString,
  481.                                     replyBuffer,   sizeof (replyBuffer),  &replyBufferSize, idleProc);    
  482.      
  483.     return ErrNo;
  484. }
  485.  
  486.  
  487.  
  488. // ---------------------------------------------------------------------------
  489. static void PostError(short errorStrId,short explanStrID)
  490. // ---------------------------------------------------------------------------
  491. //
  492. {
  493.           Str255         errorBuf, explainBuf;
  494.         SInt16         itemHit;
  495.  
  496.         GetIndString(errorBuf, kErrorStringsID, errorStrId);
  497.  
  498.         if(explanStrID) 
  499.             GetIndString(explainBuf, kErrorStringsID, explanStrID);
  500.  
  501.         StandardAlert(kAlertStopAlert,errorBuf, (explanStrID)?explainBuf:nil, nil , &itemHit);
  502. }
  503.  
  504. // ---------------------------------------------------------------------------
  505. static void TerminateConnection(void* context)
  506. // ---------------------------------------------------------------------------
  507. {
  508.     UAMArgs *theArgs = (UAMArgs *) context;
  509.      
  510. }
  511.  
  512. #pragma mark -
  513.   
  514. // ---------------------------------------------------------------------------
  515. static StringPtr    FigureAFPVersion(AFPSrvrInfo *info,ClientUAMCallbackRec *callbacks)
  516. // ---------------------------------------------------------------------------
  517. {
  518.     struct    AFPClientInfo *theClientInfo = nil;
  519.     short    index;
  520.     Ptr        versBuf;
  521.     UInt32    versBufsize;
  522.  
  523. #if 0
  524. // Hack
  525.     return "\pAFP TEST VERSION";
  526. // Hack
  527. #endif
  528.     
  529. //DebugStr("\pFigureAFPVersion");
  530.  
  531.     CallUniversalProc( callbacks->GetClientInfoUPP, kGetClientInfoProcInfo,  kAFPClientInfo, &theClientInfo);
  532.  
  533.     if(theClientInfo){                
  534.     // go through the list of AFP versions supported and try to find them
  535.     // in the SrvrInfoBuffer, first match gets it 
  536.         versBuf = (Ptr)((UInt32)info + info->fVerCountOffset+1);
  537.         versBufsize = kMaxAFPCommand - info->fVerCountOffset;    // the largest size
  538.         
  539.         for(index = 0; index < theClientInfo->fNumAFPVersions; index++){
  540.             if(FindStringInBuf(theClientInfo->fAFPVersionStrs[index],versBuf,versBufsize)){
  541.                 return theClientInfo->fAFPVersionStrs[index];
  542.             }
  543.         }
  544.     }
  545.     return    nil;
  546. }
  547.  
  548. // ---------------------------------------------------------------------------
  549. static Boolean FindStringInBuf(StringPtr string, Ptr buf, UInt32 bufSize)
  550. // ---------------------------------------------------------------------------
  551. {
  552.     Ptr        end = buf + bufSize;
  553.     Byte    len = string[0] + 1;
  554.     short    index;
  555.     
  556.     while((buf < end) && (*buf++ != string[0])) ;    // scan for the proper length
  557.  
  558.     if(!(buf < end)){
  559.         return false;
  560.     }
  561.     for(index = 1; (index < len) && (buf > end); index++){
  562.         if(*buf++ != string[index])
  563.             return false; 
  564.     }
  565.     if(!(buf < end)){
  566.         return false;
  567.     }
  568.     return true;
  569. }
  570.  
  571.  
  572.  
  573.  
  574.  
  575.